#include "widget.h"
#include "ui_widget.h"

// 三个方块代码蛇，最上面的第一个和最后面的一个通过按键进行交替删除 即snake[0]永远表示头


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle("贪吃蛇疯子");
    this->setWindowIcon(QIcon(":/icons/title.jpg"));

    qDebug()<<"x = "<<this->x()<<" y = "<<this->y()<<" height = "<<this->height()<<" width = "<<this->width();

    timer = new QTimer();
    connect(timer, &QTimer::timeout, this , &Widget::my_timeout);

    // 初始化蛇身子 3个方块
    QRectF rect(this->width()/2,this->height()/2,nodeWidth,nodeHeight);
    snakeList.append(rect);
    topAddRect();
    topAddRect();

   // 添加食物
   addFood();
}

Widget::~Widget()
{
    delete ui;
}

// 增加一个方块 左上和右下确认一个方块坐标系
void Widget::topAddRect()
{
    QPointF leftTop;                // 左上角坐标
    QPointF rightBottom;       // 右上角坐标

    if (snakeList[0].y()  <=  0) {
        // 当蛇移动到窗口顶部：确认新坐标 y = 窗口高度 - 蛇方块高度
        leftTop = QPointF(snakeList[0].x(), this->height() - nodeHeight);
        rightBottom  = QPointF(snakeList[0].x() + nodeWidth , this->height());
    }
    else {
        // 向上移动： y坐标必然减少 减少的右下角坐标为之前的下一个方块的右上角坐标
        leftTop = QPointF(snakeList[0].x(), snakeList[0].y() - nodeHeight);
        rightBottom = snakeList[0].topRight();
    }

    // 插入矩形小方块1个,由于采用的是List链表，这是典型的前插，追加
    snakeList.insert(0,QRectF(leftTop,rightBottom));
}

void Widget::downAddRect()
{
    QPointF leftTop;                // 左上角坐标
    QPointF rightBottom;       // 右上角坐标

    if (snakeList[0].y() > this->height() - nodeHeight) {
        // 当蛇移动到窗口底部：确认新坐标 y = 0
        leftTop = QPointF(snakeList[0].x(), 0);
        rightBottom  = QPointF(snakeList[0].x() + nodeWidth, 0 + nodeHeight);
    }
    else {
        // 向下移动： y坐标必然增加
        leftTop = QPointF(snakeList[0].x(), snakeList[0].y() + nodeHeight);
        rightBottom = snakeList[0].bottomRight() + QPointF(0,nodeHeight);
    }

    // 插入矩形小方块1个
    snakeList.insert(0,QRectF(leftTop,rightBottom));
}

void Widget::leftAddRect()
{
    QPointF leftTop;                // 左上角坐标
    QPointF rightBottom;       // 右上角坐标

    if (snakeList[0].x() <= 0) {
        // 当蛇移动到窗口最左部：确认新坐标 x = 窗口宽度 - 小方块宽度
        leftTop = QPointF(this->width() - nodeWidth, snakeList[0].y());
    }
    else {
        // 向左移动：x坐标必然减少
        leftTop = QPointF(snakeList[0].x() - nodeWidth, snakeList[0].y());
    }

    // 右下角坐标 = 之前一个的左上角坐标x,y + 小方块的宽高
    rightBottom  = leftTop + QPointF(nodeWidth, nodeHeight);

    // 插入矩形小方块1个
    snakeList.insert(0,QRectF(leftTop,rightBottom));
}

void Widget::rightAddRect()
{
    QPointF leftTop;                // 左上角坐标
    QPointF rightBottom;       // 右上角坐标

    if (snakeList[0].x() + nodeWidth > this->width()) {
        // 当蛇移动到窗口最右部：确认新坐标 x  = 0
        leftTop = QPointF(0, snakeList[0].y());
    }
    else {
        // 向右移动：x坐标必然增加
        leftTop = QPointF(snakeList[0].x() + nodeWidth, snakeList[0].y());
    }

    // 右下角坐标 = 之前一个的左上角坐标x,y + 小方块的宽高
    rightBottom  = leftTop + QPointF(nodeWidth, nodeHeight);

    // 插入矩形小方块1个
    snakeList.insert(0,QRectF(leftTop,rightBottom));
}

// 删除蛇身最后一个
void Widget::deleteLast()
{
    snakeList.removeLast();
}

// 食物是随机出现的
void Widget::addFood()
{
    int rectX = (qrand() % (this->width() / 20)) * 20;
    int rectY = (qrand() % (this->height() / 20)) * 20;

    // 控制小球出现的范围
    if (rectX >= 0 && rectY>=0) {
         food = QRectF(rectX, rectY, nodeWidth, nodeHeight);
         qDebug()<<"food = "<<food;
    }
}

// 蛇头和蛇身碰撞检查，其实就是蛇头和蛇尾其中一个方块重合
bool Widget::checkHit()
{
    // 整个蛇的长度都遍历一遍
    for (int i =0 ; i < snakeList.length(); i++) {
        // 从蛇头后的第一个开始检查 只要有
        for (int j=  i+ 1; j < snakeList.length();j++) {
             // rect0和rectx相等，表示它们的坐标、宽度和高度都一致
            if (snakeList[0] == snakeList[j]) {
                return true;
            }
        }
    }

    return false;
}

void Widget::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    case Qt::Key::Key_Up:
        if (moveFlag != dir_DOWN) {
            moveFlag = dir_UP;
        }
        break;
    case Qt::Key::Key_Down:
         if (moveFlag != dir_UP) {
            moveFlag = dir_DOWN ;
         }
        break;
    case Qt::Key::Key_Left:
        if (moveFlag != dir_RIGHT) {
            moveFlag = dir_LEFT;
        }
        break;
    case Qt::Key::Key_Right:
        if (moveFlag != dir_LEFT) {
            moveFlag = dir_RIGHT;
        }
        break;
    case Qt::Key_Space:
        if (gameStart == false) {
            gameStart = true;
            timer->start(startTime); // 100ms
        }
        else {
            gameStart = false;
            timer->stop();
        }
        break;
    default:
        break;
    }
}

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QPen pen;
    QBrush brush;

    QPixmap pix;
    // 绘制图片背景
    pix.load(":/icons/bg_snake.png");
    painter.drawPixmap(0,0,this->width(),this->height(),pix);

    // 绘制蛇
    pen.setColor(Qt::color0);
    brush.setColor(Qt::darkGreen);          // 绿色
    brush.setStyle(Qt::SolidPattern);       // 实线图案
    painter.setPen(pen);
    painter.setBrush(brush);

    for (int i = 0; i < snakeList.length(); i++) {
        painter.drawRect(snakeList[i]);
    }
    // 分数
    ui->label_score->setText(QString::number(snakeList.length() -3));

    // 绘制食物
    painter.drawEllipse(food);

    // 蛇头碰到蛇身结束游戏
    if (checkHit()) {
       QFont font("方正舒体",30,QFont::ExtraLight,false);
       painter.setFont(font);
       painter.drawText((this->width() - 200)/2,this->height()/2,QString("游戏结束"));

        timer->stop();
    }


    QWidget::paintEvent(event);

}

// 定时器槽函数
void Widget::my_timeout()
{
    //int count = 1;  // 采用这种方式也可以加长蛇身，不过我还是喜欢我的烂方法

    // 判断蛇是否吃到食物 是否重合[交叉；相交；贯穿；横穿；横断]  蛇变长
    if (snakeList[0].intersects(food)) {
        qDebug()<<"吃到食物 snakeList[0] = "<<snakeList[0]<<" food = "<<food;
        //count ++ ;      // 例如 2
        switch (moveFlag) {
        case dir_UP:
            this->topAddRect();         // +1
            break;
        case dir_DOWN:
            this->downAddRect();     // +1
            break;
        case dir_LEFT:
            this->leftAddRect();        // +1
            break;
        case dir_RIGHT:
            this->rightAddRect();     // +1
            break;
        default:
            break;
        }
        addFood();    // 食物位置变化
        return;
    }

    // 加长蛇身  每次在最前面增加一个
   // while (count--) {
        switch (moveFlag) {
        case dir_UP:
            this->topAddRect();         // +1
            break;
        case dir_DOWN:
            this->downAddRect();     // +1
            break;
        case dir_LEFT:
            this->leftAddRect();        // +1
            break;
        case dir_RIGHT:
            this->rightAddRect();     // +1
            break;
        default:
            break;
        }
    //}

     // 为了动态显示每次最前面插入一个，最后面就减少一个
    deleteLast();       // 删除蛇尾  -1
    this->update(); // 刷新绘制函数
}


void Widget::on_pushButton_clicked()
{
    // 通过代码在某个时刻让样式生效
    ui->pushButton->setProperty("check",false); // 设置按钮属性
    ui->pushButton->style()->unpolish(ui->pushButton); // 取消旧的外观
    ui->pushButton->style()->polish(ui->pushButton);   // 设置新的外观
    ui->pushButton->update();   // 更新生效

}
